home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Educational / RasMol / Source / abstree.c next >
Encoding:
C/C++ Source or Header  |  1995-10-10  |  37.3 KB  |  1,302 lines

  1. /* abstree.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, August 1995
  4.  * Version 2.6
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <malloc.h>
  10. #endif
  11. #ifndef sun386
  12. #include <stdlib.h>
  13. #endif
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <stdio.h>
  17. #include <math.h>
  18.  
  19. #define ABSTREE
  20. #include "molecule.h"
  21. #include "abstree.h"
  22.  
  23.  
  24. #define ExprPool    16
  25. #define SetPool     4
  26.  
  27. typedef struct _SymEntry {
  28.                 struct _SymEntry __far *lft;
  29.                 struct _SymEntry __far *rgt;
  30.                 AtomSet __far *defn;
  31.                 char *ident;
  32.                 } SymEntry;
  33.  
  34. static SymEntry __far *SymbolTable;
  35. static SymEntry __far *FreeEntry;
  36. static AtomSet __far *FreeSet;
  37. static Expr *FreeExpr;
  38. static Expr FalseExpr;
  39. static Expr TrueExpr;
  40.  
  41. /* Macros for commonly used loops */
  42. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  43.                      for(group=chain->glist;group;group=group->gnext)    \
  44.                      for(aptr=group->alist;aptr;aptr=aptr->anext)
  45.  
  46.  
  47. #define BitAcidic       0x001
  48. #define BitAliphatic    0x002
  49. #define BitAromatic     0x004
  50. #define BitBasic        0x008
  51. #define BitBuried       0x010
  52. #define BitCyclic       0x020
  53. #define BitHydrophobic  0x040
  54. #define BitMedium       0x080
  55. #define BitNeutral      0x100
  56. #define BitSmall        0x200
  57.  
  58. #define BitCharged      0x009
  59. #define BitNotLarge     0x280
  60.  
  61. /* Acyclic = !Cyclic         */
  62. /* Large = !Medium && !Small */
  63. /* Polar = !Hydrophobic      */
  64. /* Surface = !Buried         */
  65.  
  66.  
  67. #define AminoCodeMax  28
  68. static char *AminoCode = "AGLSVTKDINEPRFQYHCMWBZPPACGTX";
  69.  
  70. static int AminoProp[] = {
  71.         /*ALA*/  BitAliphatic | BitBuried | BitHydrophobic | BitNeutral |
  72.                  BitSmall,
  73.         /*GLY*/  BitAliphatic | BitHydrophobic | BitNeutral | BitSmall,
  74.         /*LEU*/  BitAliphatic | BitBuried | BitHydrophobic | BitNeutral,
  75.         /*SER*/  BitNeutral | BitSmall,
  76.         /*VAL*/  BitAliphatic | BitBuried | BitHydrophobic | BitMedium |
  77.                  BitNeutral,
  78.         /*THR*/  BitMedium | BitNeutral,
  79.         /*LYS*/  BitBasic,
  80.         /*ASP*/  BitAcidic | BitMedium,
  81.         /*ILE*/  BitAliphatic | BitBuried | BitHydrophobic | BitNeutral,
  82.         /*ASN*/  BitMedium | BitNeutral,
  83.         /*GLU*/  BitAcidic,
  84.         /*PRO*/  BitCyclic | BitHydrophobic | BitMedium | BitNeutral,
  85.         /*ARG*/  BitBasic,
  86.         /*PHE*/  BitAromatic | BitBuried | BitCyclic | BitHydrophobic |
  87.                  BitNeutral,
  88.         /*GLN*/  BitNeutral,
  89.         /*TYR*/  BitAromatic | BitCyclic | BitNeutral,
  90.         /*HIS*/  BitAromatic | BitBasic | BitCyclic | BitNeutral,
  91.         /*CYS*/  BitBuried | BitMedium | BitNeutral,
  92.         /*MET*/  BitBuried | BitHydrophobic | BitNeutral,
  93.         /*TRP*/  BitAromatic | BitBuried | BitCyclic | BitHydrophobic |
  94.                  BitNeutral,
  95.  
  96.         /*ASX*/  BitMedium | BitNeutral,
  97.         /*GLX*/  BitNeutral,
  98.         /*PCA*/  BitCyclic | BitHydrophobic | BitMedium | BitNeutral,
  99.         /*HYP*/  BitCyclic | BitMedium | BitNeutral
  100.         };
  101.  
  102.  
  103. static void FatalExprError(ptr)
  104.     char *ptr;
  105. {
  106.     char buffer[80];
  107.  
  108.     sprintf(buffer,"Expression Error: %s!",ptr);
  109.     RasMolFatalExit(buffer);
  110. }
  111.  
  112.  
  113. #ifdef FUNCPROTO
  114. /* Function Prototypes */
  115. static AtomSet __far *SetInsert( AtomSet __far*, Atom __far* );
  116. static int IsWithinRadius( AtomSet __far*, Long );
  117. static int IsSetMember( AtomSet __far* );
  118. #endif
  119.  
  120.  
  121. static AtomSet __far *SetInsert( ptr, item )
  122.     AtomSet __far *ptr;  Atom __far *item;
  123. {
  124.     register AtomSet __far *temp;
  125.     register int i;
  126.  
  127.     if( ptr && (ptr->count<SetSize) )
  128.     {   ptr->data[ptr->count] = item;
  129.         ptr->count++;
  130.         return( ptr );
  131.     }
  132.  
  133.     if( !FreeSet )
  134.     {   temp = (AtomSet __far*)_fmalloc( SetPool*sizeof(AtomSet) );
  135.         if( !temp ) FatalExprError("Memory allocation failed");
  136.         for( i=1; i<SetPool; i++ )
  137.         {    temp->next = FreeSet;
  138.              FreeSet = temp++;
  139.         }
  140.     } else
  141.     {   temp = FreeSet;
  142.         FreeSet = temp->next;
  143.     }
  144.  
  145.     temp->data[0] = item;
  146.     temp->next = ptr;
  147.     temp->count = 1;
  148.     return( temp );
  149. }
  150.  
  151.  
  152. static int IsWithinRadius( ptr, limit )
  153.     AtomSet __far *ptr;
  154.     Long limit;
  155. {
  156.     register Atom __far *aptr;
  157.     register Long dx,dy,dz;
  158.     register Long dist;
  159.     register int i;
  160.  
  161.     while( ptr )
  162.     {   for( i=0; i<ptr->count; i++ )
  163.         {    aptr = ptr->data[i];
  164.              dx = QAtom->xorg-aptr->xorg; if( (dist=dx*dx)>limit ) continue;
  165.              dy = QAtom->yorg-aptr->yorg; if( (dist+=dy*dy)>limit ) continue;
  166.              dz = QAtom->zorg-aptr->zorg; if( (dist+=dz*dz)>limit ) continue;
  167.              return( True );
  168.         }
  169.         ptr = ptr->next;
  170.     }
  171.     return( False );
  172. }
  173.  
  174.  
  175. static int IsSetMember( ptr )
  176.     AtomSet __far *ptr;
  177. {
  178.     register int i;
  179.  
  180.     while( ptr )
  181.     {   for( i=0; i<ptr->count; i++ )
  182.             if( ptr->data[i] == QAtom )
  183.                 return( True );
  184.         ptr = ptr->next;
  185.     }
  186.     return( False );
  187. }
  188.  
  189.  
  190. void DeleteAtomSet( ptr )
  191.     AtomSet __far *ptr;
  192. {
  193.     register AtomSet __far *temp;
  194.  
  195.     if( ptr )
  196.     {   temp = ptr;
  197.         while( temp->next )
  198.             temp = temp->next;
  199.         temp->next = FreeSet;
  200.         FreeSet = ptr;
  201.     }
  202. }
  203.  
  204.  
  205. Expr *AllocateNode()
  206. {
  207.     register Expr *ptr;
  208.     register int i;
  209.  
  210.     if( !FreeExpr )
  211.     {   ptr = (Expr*)malloc( ExprPool*sizeof(Expr) );
  212.         if( !ptr ) FatalExprError("Memory allocation failed");
  213.         for( i=1; i<ExprPool; i++ )
  214.         {   ptr->rgt.ptr = FreeExpr;
  215.             FreeExpr = ptr++;
  216.         }
  217.     } else
  218.     {   ptr = FreeExpr;
  219.         FreeExpr = ptr->rgt.ptr;
  220.     }
  221.     ptr->rgt.ptr = NULL;
  222.     ptr->lft.ptr = NULL;
  223.     return( ptr );
  224. }
  225.  
  226.  
  227. void DeAllocateExpr( expr )
  228.     Expr *expr;
  229. {
  230.     if( !expr ) return;
  231.     if( (expr == &FalseExpr) ||
  232.         (expr == &TrueExpr) ) 
  233.         return;
  234.  
  235.     if( expr->type!=OpWithin )
  236.     {   if( !(expr->type&(OpLftProp|OpLftVal)) )
  237.             DeAllocateExpr( expr->lft.ptr );
  238.         if( !(expr->type&(OpRgtProp|OpRgtVal)) )
  239.             DeAllocateExpr( expr->rgt.ptr );
  240.     } else DeleteAtomSet( expr->rgt.set );
  241.         
  242.     expr->rgt.ptr = FreeExpr;
  243.     FreeExpr = expr;
  244. }
  245.  
  246.  
  247. int GetElemNumber( group, aptr )
  248.     Group __far *group;
  249.     Atom __far *aptr;
  250. {
  251.     register char ch1,ch2;
  252.     register char *ptr;
  253.  
  254.     ptr = ElemDesc[aptr->refno];
  255.     if( IsNADGroup(group->refno) || IsCOAGroup(group->refno) )
  256.     {   /* Exceptions to Brookhaven Atom Naming! */
  257.         ch1 = ' ';
  258.     } else 
  259.     {   ch1 = ptr[0];
  260.         /* Handle HG, HD etc.. in Amino Acids! */
  261.         if( (ch1=='H') && IsProtein(group->refno) )
  262.             return( 1 );
  263.     }
  264.     ch2 = ptr[1];
  265.  
  266.  
  267.     switch( ch1 )
  268.     {   case(' '):  switch( ch2 )
  269.                     {   case('B'):  return(  5 );
  270.                         case('C'):  return(  6 );
  271.                         case('D'):  return(  1 );
  272.                         case('F'):  return(  9 );
  273.                         case('H'):  return(  1 );
  274.                         case('I'):  return( 53 );
  275.                         case('K'):  return( 19 );
  276.                         case('L'):  return(  1 );
  277.                         case('N'):  return(  7 );
  278.                         case('O'):  return(  8 );
  279.                         case('P'):  return( 15 );
  280.                         case('S'):  return( 16 );
  281.                         case('U'):  return( 92 );
  282.                         case('V'):  return( 23 );
  283.                         case('W'):  return( 74 );
  284.                         case('Y'):  return( 39 );
  285.                     }
  286.                     break;
  287.  
  288.         case('A'):  switch( ch2 )
  289.                     {   case('C'):  return( 89 );
  290.                         case('G'):  return( 47 );
  291.                         case('L'):  return( 13 );
  292.                         case('M'):  return( 95 );
  293.                         case('R'):  return( 18 );
  294.                         case('S'):  return( 33 );
  295.                         case('T'):  return( 85 );
  296.                         case('U'):  return( 79 );
  297.                     }
  298.                     break;
  299.  
  300.         case('B'):  switch( ch2 )
  301.                     {   case('A'):  return( 56 );
  302.                         case('E'):  return(  4 );
  303.                         case('I'):  return( 83 );
  304.                         case('K'):  return( 97 );
  305.                         case('R'):  return( 35 );
  306.                     }
  307.                     break;
  308.  
  309.         case('C'):  switch( ch2 )
  310.                     {   case('A'):  return( 20 );
  311.                         case('D'):  return( 48 );
  312.                         case('E'):  return( 58 );
  313.                         case('F'):  return( 98 );
  314.                         case('L'):  return( 17 );
  315.                         case('M'):  return( 96 );
  316.                         case('O'):  return( 27 );
  317.                         case('R'):  return( 24 );
  318.                         case('S'):  return( 55 );
  319.                         case('U'):  return( 29 );
  320.                     }
  321.                     break;
  322.  
  323.         case('D'):  if( ch2=='Y' )
  324.                         return( 66 );
  325.                     break;
  326.  
  327.         case('E'):  if( ch2=='R' )
  328.                     {   return( 68 );
  329.                     } else if( ch2=='S' )
  330.                     {   return( 99 );
  331.                     } else if( ch2=='U' )
  332.                         return( 63 );
  333.                     break;
  334.  
  335.         case('F'):  if( ch2=='E' )
  336.                     {   return(  26 );
  337.                     } else if( ch2=='M' )
  338.                     {   return( 100 );
  339.                     } else if( ch2=='R' )
  340.                         return(  87 );
  341.                     break;
  342.  
  343.         case('G'):  if( ch2=='A' )
  344.                     {   return( 31 );
  345.                     } else if( ch2=='D' )
  346.                     {   return( 64 );
  347.                     } else if( ch2=='E' )
  348.                         return( 32 );
  349.                     break;
  350.  
  351.         case('H'):  if( ch2=='E' )
  352.                     {   return(  2 );
  353.                     } else if( ch2=='F' )
  354.                     {   return( 72 );
  355.                     } else if( ch2=='G' )
  356.                     {   return( 80 );
  357.                     } else if( ch2=='O' )
  358.                         return( 67 );
  359.                     break;
  360.  
  361.         case('I'):  if( ch2=='N' )
  362.                     {   return( 49 );
  363.                     } else if( ch2=='R' )
  364.                         return( 77 );
  365.                     break;
  366.  
  367.         case('K'):  if( ch2=='R' )
  368.                         return( 36 );
  369.                     break;
  370.  
  371.         case('L'):  if( ch2=='A' )
  372.                     {   return(  57 );
  373.                     } else if( ch2=='I' )
  374.                     {   return(   3 );
  375.                     } else if( (ch2=='R') || (ch2=='W') )
  376.                     {   return( 103 );
  377.                     } else if( ch2=='U' )
  378.                         return(  71 );
  379.                     break;
  380.  
  381.         case('M'):  if( ch2=='D' )
  382.                     {   return( 101 );
  383.                     } else if( ch2=='G' )
  384.                     {   return(  12 );
  385.                     } else if( ch2=='N' )
  386.                     {   return(  25 );
  387.                     } else if( ch2=='O' )
  388.                         return(  42 );
  389.                     break;
  390.  
  391.         case('N'):  switch( ch2 )
  392.                     {   case('A'):  return(  11 );
  393.                         case('B'):  return(  41 );
  394.                         case('D'):  return(  60 );
  395.                         case('E'):  return(  10 );
  396.                         case('I'):  return(  28 );
  397.                         case('O'):  return( 102 );
  398.                         case('P'):  return(  93 );
  399.                     }
  400.                     break;
  401.  
  402.         case('O'):  if( ch2=='S' )
  403.                         return( 76 );
  404.                     break;
  405.  
  406.         case('P'):  switch( ch2 )
  407.                     {   case('A'):  return( 91 );
  408.                         case('B'):  return( 82 );
  409.                         case('D'):  return( 46 );
  410.                         case('M'):  return( 61 );
  411.                         case('O'):  return( 84 );
  412.                         case('R'):  return( 59 );
  413.                         case('T'):  return( 78 );
  414.                         case('U'):  return( 94 );
  415.                     }
  416.                     break;
  417.  
  418.         case('R'):  switch( ch2 )
  419.                     {   case('A'):  return( 88 );
  420.                         case('B'):  return( 37 );
  421.                         case('E'):  return( 75 );
  422.                         case('H'):  return( 45 );
  423.                         case('N'):  return( 86 );
  424.                         case('U'):  return( 44 );
  425.                     }
  426.                     break;
  427.  
  428.         case('S'):  switch( ch2 )
  429.                     {   case('B'):  return( 51 );
  430.                         case('C'):  return( 21 );
  431.                         case('E'):  return( 34 );
  432.                         case('I'):  return( 14 );
  433.                         case('M'):  return( 62 );
  434.                         case('N'):  return( 50 );
  435.                         case('R'):  return( 38 );
  436.                     }
  437.                     break;
  438.  
  439.         case('T'):  switch( ch2 )
  440.                     {   case('A'):  return( 73 );
  441.                         case('B'):  return( 65 );
  442.                         case('C'):  return( 43 );
  443.                         case('E'):  return( 52 );
  444.                         case('H'):  return( 90 );
  445.                         case('I'):  return( 22 );
  446.                         case('L'):  return( 81 );
  447.                         case('M'):  return( 69 );
  448.                     }
  449.                     break;
  450.  
  451.         case('X'):  if( ch2=='E' )
  452.                         return( 54 );
  453.                     break;
  454.  
  455.         case('Y'):  if( ch2=='B' )
  456.                         return( 70 );
  457.                     break;
  458.  
  459.         case('Z'):  if( ch2=='N' )
  460.                     {   return( 30 );
  461.                     } else if( ch2=='R' )
  462.                         return( 40 );
  463.                     break;
  464.     }
  465.  
  466.     if( (ch1>='0') && (ch1<='9') )
  467.         if( (ch2=='H') || (ch2=='D') )
  468.             return( 1 ); /* Hydrogen */
  469.  
  470.     return( 0 );
  471. }
  472.  
  473.  
  474. int ElemVDWRadius( elem )
  475.     int elem;
  476. {
  477.     if( !HasHydrogen )
  478.         switch( elem )
  479.         {   case(  6 ):  return( VDWCarbon );
  480.             case(  7 ):  return( VDWNitrogen );
  481.             case(  8 ):  return( VDWOxygen );    
  482.             case( 16 ):  return( VDWSulphur );
  483.         }
  484.     return( Element[elem].vdwrad );
  485. }
  486.  
  487.  
  488. static int EvaluateProperty( prop )
  489.     int prop;
  490. {
  491.     switch( prop )
  492.     {   case( PropIdent ):    return( QAtom->serno );
  493.         case( PropXCord ):    return( (int)QAtom->xorg );
  494.         case( PropYCord ):    return( (int)QAtom->yorg );
  495.         case( PropZCord ):    return( (int)QAtom->zorg );
  496.         case( PropTemp ):     return( QAtom->temp );
  497.         case( PropName ):     return( QAtom->refno );
  498.         case( PropResId ):    return( QGroup->serno );
  499.         case( PropResName ):  return( QGroup->refno );
  500.         case( PropChain ):    return( QChain->ident );
  501.         case( PropSelect ):   return( QAtom->flag&SelectFlag );
  502.         case( PropElemNo ):   return( QAtom->elemno );
  503.         case( PropModel ):    return( QChain->model );
  504.         case( PropRad ):      if( QAtom->flag&SphereFlag )
  505.                               {   return( QAtom->radius );
  506.                               } else return( 0 );
  507.  
  508.         
  509.         /* Predicates stored in flags */
  510.         case( PredBonded ):       return( !(QAtom->flag&NonBondFlag) );
  511.         case( PredHydrogen ):     return( QAtom->flag&HydrogenFlag );
  512.         case( PredHetero ):       return( QAtom->flag&HeteroFlag );
  513.         case( PredCystine ):      return( QGroup->flag&CystineFlag );
  514.         case( PredHelix ):        return( QGroup->struc&HelixFlag );
  515.         case( PredSheet ):        return( QGroup->struc&SheetFlag );
  516.         case( PredTurn ):         return( QGroup->struc&TurnFlag );
  517.  
  518.         /* Residue type predicates */
  519.         case( PredDNA ):          return( IsDNA(QGroup->refno) );
  520.         case( PredRNA ):          return( IsRNA(QGroup->refno) );
  521.         case( PredNucleic ):      return( IsNucleo(QGroup->refno) );
  522.         case( PredProtein ):      return( IsProtein(QGroup->refno) );
  523.         case( PredAmino ):        return( IsAmino(QGroup->refno) );
  524.         case( PredWater ):        return( IsWater(QGroup->refno) );
  525.         case( PredSolvent ):      return( IsSolvent(QGroup->refno) );
  526.         case( PredIon ):          return( IsIon(QGroup->refno) );
  527.  
  528.         /* General Predicates */
  529.         case( PredAlpha ):        return( IsAmino(QGroup->refno) &&
  530.                                           IsAlphaCarbon(QAtom->refno) );
  531.         case( PredMainChain ):    return( (IsAmino(QGroup->refno) && 
  532.                                            IsAminoBackbone(QAtom->refno)) ||
  533.                                           (IsNucleo(QGroup->refno) &&
  534.                                            IsNucleicBackbone(QAtom->refno)) );
  535.         case( PredSidechain ):    return( IsAmino(QGroup->refno) &&
  536.                                           !IsAminoBackbone(QAtom->refno) );
  537.         case( PredLigand ):       return( (QAtom->flag&HeteroFlag) &&
  538.                                           !IsSolvent(QGroup->refno) );
  539.  
  540.         /* Nucleic Acid Classifications */
  541.         case( PredAT ):           return( IsAdenine(QGroup->refno) ||
  542.                                           IsThymine(QGroup->refno) );
  543.         case( PredCG ):           return( IsCytosine(QGroup->refno) ||
  544.                                           IsGuanine(QGroup->refno) );
  545.         case( PredPyrimidine ):   return( IsPyrimidine(QGroup->refno) );
  546.         case( PredPurine ):       return( IsPurine(QGroup->refno) );
  547.  
  548.  
  549.         /* Amino Acid Classifications */
  550.         case( PredAcidic ):       return( IsAmino(QGroup->refno) &&
  551.                                   AminoProp[QGroup->refno]&BitAcidic );
  552.  
  553.         case( PredAcyclic ):      return( IsAmino(QGroup->refno) &&
  554.                                   !(AminoProp[QGroup->refno]&BitCyclic) );
  555.  
  556.         case( PredAliphatic ):    return( IsAmino(QGroup->refno) &&
  557.                                   AminoProp[QGroup->refno]&BitAliphatic );
  558.  
  559.         case( PredAromatic ):     return( IsAmino(QGroup->refno) &&
  560.                                   AminoProp[QGroup->refno]&BitAromatic );
  561.  
  562.         case( PredBasic ):        return( IsAmino(QGroup->refno) &&
  563.                                   AminoProp[QGroup->refno]&BitBasic );
  564.  
  565.         case( PredBuried ):       return( IsAmino(QGroup->refno) &&
  566.                                   AminoProp[QGroup->refno]&BitBuried );
  567.  
  568.         case( PredCharged ):      return( IsAmino(QGroup->refno) &&
  569.                                   AminoProp[QGroup->refno]&BitCharged );
  570.  
  571.         case( PredCyclic ):       return( IsAmino(QGroup->refno) &&
  572.                                   AminoProp[QGroup->refno]&BitCyclic );
  573.  
  574.         case( PredHydrophobic ):  return( IsAmino(QGroup->refno) &&
  575.                                   AminoProp[QGroup->refno]&BitHydrophobic );
  576.                  
  577.         case( PredLarge ):        return( IsAmino(QGroup->refno) &&
  578.                                   !(AminoProp[QGroup->refno]&BitNotLarge) );
  579.  
  580.         case( PredMedium ):       return( IsAmino(QGroup->refno) &&
  581.                                   AminoProp[QGroup->refno]&BitMedium );
  582.  
  583.         case( PredNeutral ):      return( IsAmino(QGroup->refno) &&
  584.                                   AminoProp[QGroup->refno]&BitNeutral );
  585.  
  586.         case( PredPolar ):        return( IsAmino(QGroup->refno) &&
  587.                                   !(AminoProp[QGroup->refno]&BitHydrophobic) );
  588.  
  589.         case( PredSmall ):        return( IsAmino(QGroup->refno) &&
  590.                                   AminoProp[QGroup->refno]&BitSmall );
  591.  
  592.         case( PredSurface ):      return( IsAmino(QGroup->refno) &&
  593.                                   !(AminoProp[QGroup->refno]&BitBuried) );
  594.  
  595.     }
  596.     return( True );
  597. }
  598.  
  599.  
  600. int EvaluateExpr( expr )
  601.     Expr *expr;
  602. {
  603.     register int lft, rgt;
  604.  
  605.     if( !expr )
  606.         return( True );
  607.  
  608.     if( expr->type==OpWithin )
  609.     {   if( expr->lft.limit )
  610.         {   return( IsWithinRadius(expr->rgt.set,expr->lft.limit) );
  611.         } else return( IsSetMember(expr->rgt.set) );
  612.     } else if( expr->type==OpMember )
  613.         return( IsSetMember(expr->rgt.set) );
  614.  
  615.     if( expr->type & OpLftVal )
  616.     {   lft = expr->lft.val;
  617.     } else if( expr->type & OpLftProp )
  618.     {   lft = EvaluateProperty( expr->lft.val );
  619.     } else lft = EvaluateExpr( expr->lft.ptr );
  620.  
  621.     if( OpCode(expr)==OpConst ) return( lft );
  622.     if( (OpCode(expr)==OpAnd) && !lft ) return( False );
  623.     if( (OpCode(expr)==OpOr) && lft ) return( True );
  624.     if( OpCode(expr)==OpNot ) return( !lft );
  625.  
  626.     if( expr->type & OpRgtVal )
  627.     {   rgt = expr->rgt.val;
  628.     } else if( expr->type & OpRgtProp )
  629.     {   rgt = EvaluateProperty( expr->rgt.val );
  630.     } else rgt = EvaluateExpr( expr->rgt.ptr );
  631.  
  632.     switch( OpCode(expr) )
  633.     {   case(OpOr):
  634.         case(OpAnd):     return( rgt );
  635.         case(OpLess):    return( lft<rgt );
  636.         case(OpMore):    return( lft>rgt );
  637.         case(OpEqual):   return( lft==rgt );
  638.         case(OpNotEq):   return( lft!=rgt );
  639.         case(OpLessEq):  return( lft<=rgt );
  640.         case(OpMoreEq):  return( lft>=rgt );
  641.     }
  642.     return( True );
  643. }
  644.  
  645.  
  646. AtomSet __far *BuildAtomSet( expr )
  647.     Expr *expr;
  648. {
  649.     register AtomSet __far *ptr;
  650.  
  651.     ptr = (AtomSet __far*)0;
  652.  
  653.     if( Database )
  654.         for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  655.             for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  656.                 for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  657.                     if( EvaluateExpr(expr) )
  658.                         ptr = SetInsert( ptr, QAtom );
  659.  
  660.     return( ptr );
  661. }
  662.  
  663.  
  664.  
  665. int DefineSetExpr( ident, expr )
  666.     char *ident;  Expr *expr;
  667. {
  668.     register SymEntry __far * __far *prev;
  669.     register SymEntry __far *ptr;
  670.     register AtomSet __far *set;
  671.     register int result;
  672.  
  673.     result = True;
  674.     prev = &SymbolTable;
  675.     while( *prev )
  676.     {   ptr = *prev;
  677.         result = strcmp(ident,ptr->ident);
  678.         if( !result ) break;  /* Entry Exists! */
  679.         prev = (result<0)? &(ptr->lft) : &(ptr->rgt);
  680.     }
  681.  
  682.     if( result )
  683.     {   if( FreeEntry )
  684.         {   ptr = FreeEntry;
  685.             FreeEntry = ptr->rgt;
  686.         } else /* Allocate SymEntry! */
  687.         {
  688.             ptr = (SymEntry __far*)_fmalloc(sizeof(SymEntry));
  689.             if( !ptr ) return( False );
  690.         }
  691.  
  692.         *prev = ptr;
  693.         ptr->ident = ident;
  694.         ptr->defn = (void __far*)0;
  695.         ptr->lft = (void __far*)0;
  696.         ptr->rgt = (void __far*)0;
  697.     } else free(ident);
  698.  
  699.     if( expr )
  700.     {   set = BuildAtomSet(expr);
  701.         if( ptr->defn )
  702.             DeleteAtomSet(ptr->defn);
  703.         DeAllocateExpr(expr);
  704.         ptr->defn = set;
  705.     } else ptr->defn = (void __far*)0;
  706.     return( True );
  707. }
  708.  
  709.  
  710. Expr *LookUpSetExpr( ident )
  711.     char *ident;
  712. {
  713.     register SymEntry __far *ptr;
  714.     register Expr *expr;
  715.     register int result;
  716.  
  717.     result = True;
  718.     ptr = SymbolTable;
  719.     while( ptr )
  720.     {   result = strcmp(ident,ptr->ident);
  721.         if( !result ) break;  /* Entry Exists! */
  722.         ptr = (result<0)? ptr->lft : ptr->rgt;
  723.     }
  724.  
  725.     if( !result )
  726.     {   expr = AllocateNode();
  727.         expr->type = OpMember;
  728.         expr->rgt.set = ptr->defn;
  729.     } else expr = (Expr*)0;
  730.     return( expr );
  731. }
  732.  
  733.  
  734. static int ElemCompare( ident, elem )
  735.     char *ident, *elem;
  736. {
  737.     while( *elem )
  738.         if( *elem++ != *ident++ )
  739.             return( False );
  740.  
  741.     /* Handle Plurals */
  742.     if( (ident[0]=='S') && !ident[1] )
  743.         return( (elem[-1]!='S') && (elem[-1]!='Y') );
  744.     return( !*ident );
  745. }
  746.  
  747.  
  748. Expr *LookUpElement( ident )
  749.     char *ident;
  750. {
  751.     register Expr *expr;
  752.     register int elem;
  753.  
  754.     for( elem=1; elem<MAXELEMNO; elem++ )
  755.         if( ElemCompare(ident,Element[elem].name) )
  756.             break;
  757.  
  758.     /* Handle Difficult Plurals & US Spelling! */
  759.     if( elem == MAXELEMNO )
  760.     {   if( *ident=='A' )
  761.         {   if( ElemCompare(ident,"ALUMINUM") )
  762.             {   elem = 13;
  763.             } else if( !strcmp(ident,"ANTIMONIES") )
  764.                 elem = 51;
  765.         } else if( *ident=='C' )
  766.         {   if( ElemCompare(ident,"CESIUM") )
  767.                 elem = 55;
  768.         } else if( *ident=='M' )
  769.         {   if( !strcmp(ident,"MERCURIES") )
  770.                 elem = 80;
  771.         } else if( *ident=='P' )
  772.         {   if( !strcmp(ident,"PHOSPHORUSES") )
  773.                 elem = 8;
  774.         } else if( *ident=='S' )
  775.         {   if( ElemCompare(ident,"SULFUR") )
  776.                 elem = 16;
  777.         }
  778.     }
  779.  
  780.     if( elem<MAXELEMNO )
  781.     {   expr = AllocateNode();
  782.         expr->type = OpEqual|OpLftProp|OpRgtVal;
  783.         expr->lft.val = PropElemNo;
  784.         expr->rgt.val = elem;
  785.     } else expr = (Expr*)0;
  786.     return( expr );
  787. }
  788.  
  789.  
  790.  
  791. static int MatchWildName( src, dst, size, len )
  792.     char *src, *dst; int size, len;
  793. {
  794.     register int i, left;
  795.  
  796.     left = size;
  797.     while( *dst==' ' )
  798.     {   dst++; left--;
  799.     }
  800.  
  801.     for( i=0; i<len; i++ )
  802.     {   if( left )
  803.         {   if( (*dst==*src) || (*src=='?') )
  804.             {   dst++;  src++;  left--;
  805.             } else return( False );
  806.         } else if( *src++ != '?' )
  807.             return( False );
  808.     }
  809.  
  810.     while( left )
  811.          if( *dst++!=' ' )
  812.          {   return( False );
  813.          } else left--;
  814.     return( True );
  815. }
  816.  
  817.  
  818.  
  819. int ParsePrimitiveExpr( orig )
  820.     char **orig;
  821. {
  822.     static char NameBuf[4];
  823.     register Expr *tmp1,*tmp2;
  824.     register Expr *wild;
  825.     register char *ptr;
  826.     register int i, j;
  827.     register int neg;
  828.     register int ch;
  829.     
  830.     QueryExpr = &TrueExpr;
  831.     ptr = *orig;
  832.     ch = *ptr++;
  833.     i = 0;
  834.  
  835.     if( ch != ':' )
  836.     {   /* Parse Residue Name */
  837.         if( ch != '*' )
  838.         {   if( ch == '[' )
  839.             {   i = 0;
  840.                 while( (ch = *ptr++) != ']' )
  841.                     if( ch && (i<3) )
  842.                     {   NameBuf[i++] = ToUpper(ch);
  843.                     } else return( False );
  844.                 ch = *ptr++;
  845.             } else
  846.                 for( i=0; i<3; i++ )
  847.                     if( isalpha(ch) )
  848.                     {   NameBuf[i] = ToUpper(ch);
  849.                         ch = *ptr++;
  850.                     } else if( (ch=='?') || (ch=='%') )
  851.                     {   NameBuf[i] = '?';
  852.                         ch = *ptr++;
  853.                     } else break;
  854.             if( !i ) return( False );
  855.  
  856.             wild = &FalseExpr;
  857.             for( j=0; j<ResNo; j++ )
  858.                 if( MatchWildName(NameBuf,Residue[j],3,i) )
  859.                 {   tmp1 = AllocateNode();
  860.                     tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  861.                     tmp1->lft.val = PropResName;
  862.                     tmp1->rgt.val = j;
  863.  
  864.                     tmp2 = AllocateNode();
  865.                     tmp2->type = OpOr;
  866.                     tmp2->lft.ptr = tmp1;
  867.                     tmp2->rgt.ptr = wild;
  868.                     wild = tmp2;
  869.                 }
  870.             QueryExpr = wild;
  871.         } else ch = *ptr++;
  872.  
  873.         /* Parse Residue Number */
  874.         if( ch != '*' )
  875.         {   if( ch == '-' )
  876.             {   ch = *ptr++;
  877.                 neg = True;
  878.             } else neg = False;
  879.  
  880.             if( isdigit(ch) )
  881.             {   i = ch-'0';
  882.                 while( isdigit(*ptr) )
  883.                     i = 10*i + (*ptr++)-'0';
  884.  
  885.                 tmp1 = AllocateNode();
  886.                 tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  887.                 tmp1->rgt.val = neg? -i : i;
  888.                 tmp1->lft.val = PropResId;
  889.                 if( QueryExpr != &TrueExpr )
  890.                 {   tmp2 = AllocateNode();
  891.                     tmp2->type = OpAnd;
  892.                     tmp2->rgt.ptr = QueryExpr;
  893.                     tmp2->lft.ptr = tmp1;
  894.                     QueryExpr = tmp2;
  895.                 } else QueryExpr = tmp1;
  896.                 ch = *ptr++;
  897.             } else if( neg )
  898.                 return( False );
  899.         } else ch = *ptr++;
  900.     }
  901.  
  902.     /* Parse Chain Ident */
  903.     if( ch==':' )
  904.         ch = *ptr++;
  905.  
  906.     if( isalnum(ch) )
  907.     {   ch = ToUpper(ch);
  908.  
  909.         tmp1 = AllocateNode();
  910.         tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  911.         tmp1->lft.val = PropChain;
  912.         tmp1->rgt.val = ch;
  913.         if( QueryExpr != &TrueExpr )
  914.         {   tmp2 = AllocateNode();
  915.             tmp2->type = OpAnd;
  916.             tmp2->rgt.ptr = QueryExpr;
  917.             tmp2->lft.ptr = tmp1;
  918.             QueryExpr = tmp2;
  919.         } else QueryExpr = tmp1;
  920.         ch = *ptr++;
  921.     } else if( (ch=='?') || (ch=='%') || (ch=='*') )
  922.         ch = *ptr++;
  923.  
  924.     /* Parse Model Number */
  925.     if( ch == ':' )
  926.     {   ch = *ptr++;
  927.         if( isdigit(ch) )
  928.         {   i = ch-'0';
  929.             while( isdigit(*ptr) )
  930.                 i = 10*i + (*ptr++)-'0';
  931.  
  932.             tmp1 = AllocateNode();
  933.             tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  934.             tmp1->lft.val = PropModel;
  935.             tmp1->rgt.val = i;
  936.             if( QueryExpr != &TrueExpr )
  937.             {   tmp2 = AllocateNode();
  938.                 tmp2->type = OpAnd;
  939.                 tmp2->rgt.ptr = QueryExpr;
  940.                 tmp2->lft.ptr = tmp1;
  941.                 QueryExpr = tmp2;
  942.             } else QueryExpr = tmp1;
  943.             ch = *ptr++;
  944.         } else return( False );
  945.     }
  946.  
  947.     /* Parse Atom Name */
  948.     if( ch == '.' )
  949.     {   ch = *ptr++;
  950.         if( ch!='*' )
  951.         {   for( i=0; i<4; i++ )
  952.                 if( isalnum(ch) || ch=='\'' || ch=='*' )
  953.                 {   NameBuf[i] = ToUpper(ch);
  954.                     ch = *ptr++;
  955.                 } else if( (ch=='?') || (ch=='%') || (ch=='#') )
  956.                 {   NameBuf[i] = '?';
  957.                     ch = *ptr++;
  958.                 } else break;
  959.             if( !i ) return( False );
  960.  
  961.  
  962.             wild = &FalseExpr;
  963.             for( j=0; j<ElemNo; j++ )
  964.                 if( MatchWildName(NameBuf,ElemDesc[j],4,i) )
  965.                 {   tmp1 = AllocateNode();
  966.                     tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  967.                     tmp1->lft.val = PropName;
  968.                     tmp1->rgt.val = j;
  969.  
  970.                     tmp2 = AllocateNode();
  971.                     tmp2->type = OpOr;
  972.                     tmp2->lft.ptr = tmp1;
  973.                     tmp2->rgt.ptr = wild;
  974.                     wild = tmp2;
  975.                 }
  976.  
  977.             if( (QueryExpr == &TrueExpr) || (wild == &FalseExpr) )
  978.             {   DeAllocateExpr(QueryExpr);
  979.                 QueryExpr=wild;
  980.             } else
  981.             {   tmp1 = AllocateNode();
  982.                 tmp1->type = OpAnd;
  983.                 tmp1->lft.ptr = QueryExpr;
  984.                 tmp1->rgt.ptr = wild;
  985.                 QueryExpr = tmp1;
  986.             }
  987.         } else ch = *ptr++;
  988.     }
  989.     *orig = --ptr;
  990.     return( !ch || isspace(ch) || ispunct(ch) );
  991. }
  992.  
  993.  
  994. static char *FormatInteger( ptr, value )
  995.     char *ptr; int value;
  996. {
  997.     auto char buffer[10];
  998.     register char *tmp;
  999.  
  1000.     if( value<0 )
  1001.     {   value = -value;
  1002.         *ptr++ = '-';
  1003.     }
  1004.  
  1005.     if( value>9 )
  1006.     {   tmp = buffer;
  1007.         while( value>9 )
  1008.         {   *tmp++ = (value%10) + '0';
  1009.             value /= 10;
  1010.         }
  1011.  
  1012.         *ptr++ = value + '0';
  1013.         do { tmp--; 
  1014.             *ptr++ = *tmp;
  1015.         } while( tmp != buffer );
  1016.     } else *ptr++ = value + '0';
  1017.     return( ptr );
  1018. }
  1019.  
  1020.  
  1021. void FormatLabel( chain, group, aptr, label, ptr )
  1022.     Chain __far *chain;
  1023.     Group __far *group;
  1024.     Atom __far *aptr;
  1025.     char *label, *ptr;
  1026. {
  1027.     register char ch;
  1028.     register int i,j;
  1029.  
  1030.     while( *label )
  1031.     {  ch = *label++;
  1032.        if( ch=='%' )
  1033.        {   ch = *label++;
  1034.            if( isupper(ch) )
  1035.              ch = tolower(ch);
  1036.  
  1037.            switch( ch )
  1038.            {   case('a'):  /* Atom Name */
  1039.                            i = aptr->refno;
  1040.                            for( j=0; j<4; j++ )
  1041.                                if( ElemDesc[i][j]!=' ' )
  1042.                                    *ptr++ = ElemDesc[i][j];
  1043.                            break;
  1044.  
  1045.                case('b'):  /* Temperature/B-factor */
  1046.                case('t'):  ptr = FormatInteger(ptr,aptr->temp);
  1047.                            break;
  1048.  
  1049.                case('c'):  /* Chain Identifier */
  1050.                case('s'):  *ptr++ = chain->ident;
  1051.                            break;
  1052.  
  1053.                case('e'):  /* Element Type */
  1054.                            i = aptr->elemno;
  1055.                            *ptr++ = Element[i].symbol[0];
  1056.                            if( Element[i].symbol[1]!=' ' )
  1057.                                *ptr++ = Element[i].symbol[1];
  1058.                            break;
  1059.  
  1060.                case('i'):  /* Atom Number */
  1061.                            ptr = FormatInteger(ptr,aptr->serno);
  1062.                            break;
  1063.  
  1064.                case('m'):  /* Amino (Nucliec) Acid Code */
  1065.                            if( group->refno <= AminoCodeMax )
  1066.                            {   *ptr++ = AminoCode[group->refno];
  1067.                            } else *ptr++ = '?';
  1068.                            break;
  1069.  
  1070.                case('n'):  /* Residue Name   */
  1071.                            i = group->refno;
  1072.                            for( j=0; j<3; j++ )
  1073.                                if( Residue[i][j]!=' ' )
  1074.                                    *ptr++ = Residue[i][j];
  1075.                            break;
  1076.  
  1077.                case('r'):  /* Residue Number */
  1078.                            ptr = FormatInteger(ptr,group->serno);
  1079.                            break;
  1080.  
  1081.                case('%'):  *ptr++ = '%';
  1082.                            break;
  1083.            }
  1084.        } else if( (ch>=' ') && (ch<='~') )
  1085.            *ptr++ = ch;
  1086.     }
  1087.     *ptr = '\0';
  1088. }
  1089.  
  1090.  
  1091. #ifdef FUNCPROTO
  1092. /* Function Prototypes */
  1093. static void DeleteSymEntry( SymEntry __far* );
  1094. #endif
  1095.  
  1096.  
  1097. static void DeleteSymEntry( ptr )
  1098.     SymEntry __far *ptr;
  1099. {
  1100.     if( ptr->lft )
  1101.         DeleteSymEntry( ptr->lft );
  1102.     if( ptr->rgt )
  1103.         DeleteSymEntry( ptr->rgt );
  1104.  
  1105.     if( ptr->defn )
  1106.         DeleteAtomSet( ptr->defn );
  1107.     free( ptr->ident );
  1108.  
  1109.     ptr->rgt = FreeEntry;
  1110.     FreeEntry = ptr;
  1111. }
  1112.  
  1113.  
  1114. void ResetSymbolTable()
  1115. {
  1116.     if( SymbolTable )
  1117.     {   DeleteSymEntry(SymbolTable);
  1118.         SymbolTable = (void __far*)0;
  1119.     }
  1120. }
  1121.  
  1122.  
  1123. double CalcDistance( atm1, atm2 )
  1124.     Atom __far *atm1;
  1125.     Atom __far *atm2;
  1126. {
  1127.     register Long dx,dy,dz;
  1128.     register double dist2;
  1129.  
  1130.     dx = atm1->xorg - atm2->xorg;
  1131.     dy = atm1->yorg - atm2->yorg;
  1132.     dz = atm1->zorg - atm2->zorg;
  1133.     if( dx || dy || dz )
  1134.     {   dist2 = dx*dx + dy*dy + dz*dz;
  1135.         return( sqrt(dist2)/250.0 );
  1136.     } else return( 0.0 );
  1137. }
  1138.  
  1139.  
  1140. double CalcAngle( atm1, atm2, atm3 )
  1141.     Atom __far *atm1;
  1142.     Atom __far *atm2;
  1143.     Atom __far *atm3;
  1144. {
  1145.     register double ulen2,vlen2;
  1146.     register double ux,uy,uz;
  1147.     register double vx,vy,vz;
  1148.     register double temp;
  1149.  
  1150.     ux = atm1->xorg - atm2->xorg;
  1151.     uy = atm1->yorg - atm2->yorg;
  1152.     uz = atm1->zorg - atm2->zorg;
  1153.     if( !ux && !uy && !uz )
  1154.         return( 0.0 );
  1155.     ulen2 = ux*ux + uy*uy + uz*uz;
  1156.  
  1157.     vx = atm3->xorg - atm2->xorg;
  1158.     vy = atm3->yorg - atm2->yorg;
  1159.     vz = atm3->zorg - atm2->zorg;
  1160.     if( !vx && !vy && !vz )
  1161.         return( 0.0 );
  1162.     vlen2 = vx*vx + vy*vy + vz*vz;
  1163.  
  1164.     temp = (ux*vx + uy*vy + uz*vz)/sqrt(ulen2*vlen2);
  1165.     return( Rad2Deg*acos(temp) );
  1166. }
  1167.  
  1168.  
  1169. double CalcTorsion( atm1, atm2, atm3, atm4 )
  1170.     Atom __far *atm1;  Atom __far *atm2;
  1171.     Atom __far *atm3;  Atom __far *atm4;
  1172. {
  1173.     register double ax, ay, az;
  1174.     register double bx, by, bz;
  1175.     register double cx, cy, cz;
  1176.     register double c12,c13,c23;
  1177.     register double s12,s23;
  1178.  
  1179.     register double cossq,sgn,om;
  1180.     register double cosom,sinom;
  1181.     register double len;
  1182.  
  1183.     ax = atm2->xorg - atm1->xorg;
  1184.     ay = atm2->yorg - atm1->yorg;
  1185.     az = atm2->zorg - atm1->zorg;
  1186.     if( !ax && !ay && !az )
  1187.         return( 0.0 );
  1188.  
  1189.     bx = atm3->xorg - atm2->xorg;
  1190.     by = atm3->yorg - atm2->yorg;
  1191.     bz = atm3->zorg - atm2->zorg;
  1192.     if( !bx && !by && !bz )
  1193.         return( 0.0 );
  1194.  
  1195.     cx = atm4->xorg - atm3->xorg;
  1196.     cy = atm4->yorg - atm3->yorg;
  1197.     cz = atm4->zorg - atm3->zorg;
  1198.     if( !cx && !cy && !cz )
  1199.         return( 0.0 );
  1200.  
  1201.  
  1202.     len = sqrt(ax*ax + ay*ay + az*az);
  1203.     ax /= len;  ay /= len;  az /= len;
  1204.     len = sqrt(bx*bx + by*by + bz*bz);
  1205.     bx /= len;  by /= len;  bz /= len;
  1206.     len = sqrt(cx*cx + cy*cy + cz*cz);
  1207.     cx /= len;  cy /= len;  cz /= len;
  1208.  
  1209.     c12 = ax*bx + ay*by + az*bz;
  1210.     c13 = ax*cx + ay*cy + az*cz;
  1211.     c23 = bx*cx + by*cy + bz*cz;
  1212.  
  1213.     s12 = sqrt(1.0-c12*c12);
  1214.     s23 = sqrt(1.0-c23*c23);
  1215.  
  1216.     cosom = (c12*c23-c13)/(s12*s23);
  1217.     cossq = cosom*cosom;
  1218.  
  1219.     if( cossq >= 1.0 )
  1220.     {   if( cosom < 0.0 )
  1221.         {    return( 180.0 );
  1222.         } else return( 0.0 );
  1223.     }
  1224.  
  1225.     sinom = sqrt(1.0-cossq);
  1226.     om = Rad2Deg*atan2(sinom,cosom);
  1227.  
  1228.     sgn =  ax*((by*cz)-(bz*cy));
  1229.     sgn += ay*((bz*cx)-(bx*cz));
  1230.     sgn += az*((bx*cy)-(by*cx));
  1231.  
  1232.     return( (sgn<0)? -om : om );
  1233. }
  1234.  
  1235.  
  1236. #ifndef ABSTREE
  1237. double CalcDihedral( atm1, atm2, atm3, atm4 )
  1238.     Atom __far *atm1;  Atom __far *atm2;
  1239.     Atom __far *atm3;  Atom __far *atm4;
  1240. {
  1241.     return( 180.0 - CalcTorsion(atm1,atm2,atm3,atm4) );
  1242. }
  1243.  
  1244.  
  1245. /* Note: curr == prev->gnext! */
  1246. double CalcPhiAngle( prev, curr )
  1247.     Group __far *prev;
  1248.     Group __far *curr;
  1249. {
  1250.     Atom __far *prevc;
  1251.     Atom __far *currca;
  1252.     Atom __far *currc;
  1253.     Atom __far *currn;
  1254.  
  1255.     if( !(prevc  = FindGroupAtom(prev,2)) ) return( 360.0 );
  1256.     if( !(currca = FindGroupAtom(curr,1)) ) return( 360.0 );
  1257.     if( !(currc  = FindGroupAtom(curr,2)) ) return( 360.0 );
  1258.     if( !(currn  = FindGroupAtom(curr,0)) ) return( 360.0 );
  1259.  
  1260.     return( CalcDihedral(prevc,currn,currca,currc) );
  1261. }
  1262.  
  1263.  
  1264. /* Note: next == curr->gnext! */
  1265. double CalcPsiAngle( curr, next )
  1266.     Group __far *curr;
  1267.     Group __far *next;
  1268. {
  1269.     Atom __far *nextn;
  1270.     Atom __far *currca;
  1271.     Atom __far *currc;
  1272.     Atom __far *currn;
  1273.  
  1274.     if( !(nextn  = FindGroupAtom(next,0)) ) return( 360.0 );
  1275.     if( !(currca = FindGroupAtom(curr,1)) ) return( 360.0 );
  1276.     if( !(currc  = FindGroupAtom(curr,2)) ) return( 360.0 );
  1277.     if( !(currn  = FindGroupAtom(curr,0)) ) return( 360.0 );
  1278.  
  1279.     return( CalcDihedral(currn,currca,currc,nextn) );
  1280. }
  1281. #endif
  1282.  
  1283.  
  1284. void InitialiseAbstree()
  1285. {
  1286.     FalseExpr.type = OpConst | OpLftVal | OpRgtVal;
  1287.     FalseExpr.rgt.val = FalseExpr.lft.val = 0;
  1288.  
  1289.     TrueExpr.type = OpConst | OpLftVal | OpRgtVal;
  1290.     TrueExpr.rgt.val = TrueExpr.lft.val = 1;
  1291.  
  1292.     QChain = (void __far*)0;
  1293.     QGroup = (void __far*)0;
  1294.     QAtom = (void __far*)0;
  1295.  
  1296.     SymbolTable = (void __far*)0;
  1297.  
  1298.     FreeEntry = (void __far*)0;
  1299.     FreeSet = (void __far*)0;
  1300.     FreeExpr = NULL;
  1301. }
  1302.